"""
图像校正：透视变换
"""
import cv2
import math
import numpy as np

# 读取图像
img = cv2.imread('../data/paper.jpg')

# 灰度化
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 图像模糊处理
blured = cv2.GaussianBlur(img_gray,(3,3),0)
# cv2.imshow('blured',blured)

# 图像膨胀
dilate = cv2.dilate(blured,(3,3))

# 边缘检测 Canny
canny = cv2.Canny(dilate,50,150)
# cv2.imshow('canny',canny)

# 查找轮廓点
cnts,hie = cv2.findContours(canny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
# cv2.drawContours(img,cnts,-1,(0,0,255))
# cv2.imshow('img_cnt',img)

docCnt = None
if len(cnts) > 0:
    # 根据面积对轮廓进行排序
    cnts = sorted(cnts,key=cv2.contourArea,reverse=True)
    # 遍历排序后的轮廓
    for cnt in cnts:
        # 对每个轮廓画逼近多边形
        eps = 0.02 * cv2.arcLength(cnt,True)
        approx = cv2.approxPolyDP(cnt,eps,True)
        print(approx)
        # 判断逼近多边形的轮廓是否为4，如果为4，保存轮廓的四个点
        if len(approx) == 4:
            docCnt = approx
            break
# print(docCnt)

# 保存顶点坐标
points = []
# 绘制顶点
for peak in docCnt:
    peak = peak[0]
    cv2.circle(img,tuple(peak),10,(0,0,255))
    points.append(peak)

# cv2.imshow('point',img)

# 确定图片的高度和宽度
# points的顺序是按左上角，左下角，右下角，右上角
h = int(math.sqrt((points[0][0] - points[1][0])**2 + (points[0][1] - points[1][1])**2))
w = int(math.sqrt((points[0][0] - points[3][0])**2 + (points[0][1] - points[3][1])**2))

# 构建透视变换的两组坐标
# 原坐标
src = np.float32([points[0],
                  points[1],
                  points[2],
                  points[3]])
# 新坐标
dst = np.float32([[0,0],
                  [0,h],
                  [w,h],
                  [w,0]])
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(src,dst)
# 进行透视变换
result = cv2.warpPerspective(img_gray,M,(w,h))

# 展示转换的图片
cv2.imshow('result',result)

# 等待用户按下任意键
cv2.waitKey()
# 关闭所有窗口
cv2.destroyAllWindows()